package com.bdqn.controller;

import com.alibaba.fastjson.JSON;
import com.bdqn.common.Constants;
import com.bdqn.common.PageSupport;
import com.bdqn.pojo.SysRole;
import com.bdqn.pojo.SysUser;
import com.bdqn.service.SysRoleService;
import com.bdqn.service.SysUserService;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * IndexController
 *
 * @author LILIBO
 * @since 2021-12-24
 */
@Controller
// @RestController // REST风格：所有方法不再返回视图名称，而是直接返回数据
@RequestMapping("/user")
public class UserController {

    private static final Logger logger = Logger.getLogger(UserController.class);

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysRoleService sysRoleService;

    /**
     * 去到登录页
     */
    @GetMapping("/login")
    public String login() {
        return "login";
    }

    /**
     * 用户点击登录按钮进行登录
     */
    @PostMapping("/login")
    public String login(Model model, HttpSession session, @RequestParam String account, @RequestParam String password) {
        // 调用业务逻辑层进行登录验证
        SysUser loginUser = sysUserService.login(account, password);
        // 账号或密码错误
        if (loginUser == null) {
            model.addAttribute("error", "账号或密码错误，请重新登录");
            return "login";
        }
        // 账号密码验证成功
        session.setAttribute(Constants.USER_SESSION, loginUser);
        return "frame";
    }

    /**
     * 退出登录，清除Session中的数据，并销毁当前Session
     */
    @GetMapping("/logout")
    public String logout(HttpSession session) {
        // 清除Session中登录者的数据
        session.removeAttribute(Constants.USER_SESSION);
        session.invalidate(); // 将当前Session作废
        return "login";
    }

    @GetMapping("/list")
    public String list(Model model, String queryRealName, Long queryRoleId, @RequestParam(value = "pageIndex", required = false, defaultValue = "1") Integer pageIndex) {
        // 接收页面传递的参数
        SysUser sysUser = new SysUser();
        sysUser.setRoleId(queryRoleId);
        sysUser.setRealName(queryRealName);

        PageSupport page = new PageSupport();
        page.setCurrentPageNo(pageIndex); // 当前查询第几页

        // 即时查询符合条件的总记录数
        page.setTotalCount(sysUserService.getPageListTotal(sysUser)); // 总数据量
        List<SysUser> pageList = sysUserService.getPageList(sysUser, page); // List<SysUser> userList = sysUserService.getList(sysUser);

        // 查询全部角色数据填充下拉列表
        List<SysRole> roleList = sysRoleService.getList(null);

        // 数据回显（将用户提交的查询条件重新赋值到页面显示）
        model.addAttribute("queryRealName", queryRealName);
        model.addAttribute("queryRoleId", queryRoleId);
        model.addAttribute("pageIndex", pageIndex);
        // ① 角色列表，填充页面搜索下拉框
        model.addAttribute("roleList", roleList);
        // ② 用户列表，填充页面表格
        model.addAttribute("userList", pageList);
        // ③ 分页数据，填充页面分页控件
        model.addAttribute("page", page);
        return "sysUser/list";
    }

    /**
     * 跳转到添加页面
     * @param sysUser 使用 @ModelAttribute("sysUser") 注解绑定对象数据到<fm:form method="post" modelAttribute="sysUser">表单
     */
    // @GetMapping("/add")
    public String toAdd(@ModelAttribute("sysUser") SysUser sysUser) {
        return "sysUser/add";
    }

    /**
     * 添加用户（后端数据验证）
     */
    // @PostMapping("/add")
    public String add(@Valid SysUser sysUser, BindingResult bindingResult, HttpSession session, @RequestParam(value = "attachs", required = false) MultipartFile[] attachs) {
        // 后端数据校验
        if (bindingResult.hasErrors()) {
            logger.debug("/user/add 添加用户验证失败");
            return "sysUser/add";
        }

        // 从Session中获取当前登录用户
        SysUser loginUser = (SysUser) session.getAttribute(Constants.USER_SESSION);
        // 设置现在新添加的用户是由哪个账号创建的（填充数据库中createdUserId字段）
        sysUser.setCreatedUserId(loginUser.getId());

        // 将数据保存到数据库
        boolean flag = sysUserService.add(sysUser);
        logger.debug("/user/add " + flag + "\n" + sysUser.toString());
        // 添加功能完成，跳转到列表页面
        return "redirect:/user/list"; // 使用重定向（让浏览器重新发起请求）
    }

    @GetMapping("/add")
    public String toAdd(Model model) {
        // 查询全部角色数据填充下拉列表
        List<SysRole> roleList = sysRoleService.getList(null);
        // 角色列表，填充页面搜索下拉框
        model.addAttribute("roleList", roleList);
        return "sysUser/add";
    }

    /**
     * 验证账号是否存在
     */
    @ResponseBody // 让返回内容原样输出到页面（通常用于Ajax方式处理）
    @GetMapping(value = "/userExist", produces = {"application/json;charset=UTF-8"})
    public String userExist(String account) {
        SysUser sysUser = sysUserService.getAccountExist(account);
        Map<String, Object> result = new HashMap<>();
        int userExist = -1; // 账号是否存在标记
        if (sysUser == null) {
            userExist = 0; // 账号不存在，可以使用
        } else {
            userExist = 1; // 账号已存在，不能使用
        }
        result.put("exist", userExist);
        return JSON.toJSONString(result); // {"exist":0}
    }

    /**
     * 添加用户（带文件上传）
     */
    @PostMapping("/add")
    public String add(HttpServletRequest request, HttpSession session, SysUser sysUser, @RequestParam(value = "idPic", required = false) MultipartFile idPic, @RequestParam(value = "workPic", required = false) MultipartFile workPic) {
        // 从Session中获取当前登录用户
        SysUser loginUser = (SysUser) session.getAttribute(Constants.USER_SESSION);
        // 设置现在新添加的用户是由哪个账号创建的（填充数据库中createdUserId字段）
        sysUser.setCreatedUserId(loginUser.getId());

        // 文件上传到服务器的真实位置
        String uploadPath = session.getServletContext().getRealPath(Constants.UPLOAD_PATH);

        // 上传身份证照片
        if (idPic != null) {
            String idPicPath = multipartFileUpload(uploadPath, request, idPic);
            if (idPicPath == null) {
                String uploadFileError = (String) request.getAttribute("uploadFileError");
                request.setAttribute("workPicUploadError", uploadFileError);
                request.removeAttribute("uploadFileError"); // 临时使用，使用完毕后移除信息
                return "sysUser/add";
            }
            // 将上传后的图片路径设置到属性，最终保存到数据库
            sysUser.setIdPicPath(idPicPath);
        }

        // 上传工作证照片
        if (workPic != null) {
            String workPicPath = multipartFileUpload(uploadPath, request, workPic);
            if (workPicPath == null) {
                String uploadFileError = (String) request.getAttribute("uploadFileError");
                request.setAttribute("workPicUploadError", uploadFileError);
                request.removeAttribute("uploadFileError"); // 临时使用，使用完毕后移除信息
                return "sysUser/add";
            }
            // 将上传后的图片路径设置到属性，最终保存到数据库
            sysUser.setWorkPicPath(workPicPath);
        }

        // 将数据保存到数据库
        boolean flag = sysUserService.add(sysUser);
        logger.debug("/user/add " + flag + "\n" + sysUser.toString());
        // 添加功能完成，跳转到列表页面
        return "redirect:/user/list"; // 使用重定向（让浏览器重新发起请求）
    }

    /**
     * 多部件文件上传（错误信息临时保存在request作用域uploadFileError属性中）
     *
     * @return 成功返回文件上传地址，返回null表示文件上传失败
     */
    public String multipartFileUpload(String uploadPath, HttpServletRequest request, MultipartFile multipartFile) {
        String uploadFilePath = null; // 文件上传地址，返回null表示文件上传失败

        // 定义文件存放目录
        logger.debug("上传文件路径：" + uploadPath);

        if (!multipartFile.isEmpty()) {
            // 获取上传的文件信息
            String originalFile = multipartFile.getOriginalFilename(); // 原文件名称
            logger.debug("原文件名称为：" + originalFile);
            String prefix = FilenameUtils.getExtension(originalFile); // 原文件后缀
            logger.debug("原文件后缀为：" + prefix);
            long fileSize = multipartFile.getSize(); // 原文件大小
            logger.debug("上传文件大小：" + fileSize);

            // 判断上传的文件是否符合要求
            if (fileSize > Constants.MAX_FILE_SIZE) { // 上传文件大小不能超过500KB
                request.setAttribute("uploadFileError", " * 上传文件大小不得超过 5MB");
                return uploadFilePath;
            }
            if (!(prefix.equalsIgnoreCase("jpg") || prefix.equalsIgnoreCase("jpeg") || prefix.equalsIgnoreCase("png") || prefix.equalsIgnoreCase("pneg"))) {
                request.setAttribute("uploadFileError", " * 上传文件格式只能是jpg、jpeg、png、pneg");
                return uploadFilePath;
            }

            // 确定文件存储名称
            String fileName = System.currentTimeMillis() + RandomUtils.nextInt(0, 1000) + "_Personal." + prefix;
            logger.debug("新生成的文件名为：" + fileName);

            // 将上传的文件保存到目标位置
            File targetFile = new File(uploadPath);
            if (!targetFile.exists()) {
                targetFile.mkdirs(); // 如果目录不存在则生成目录
            }
            // 保存文件
            try {
                // 存储物理地址 + 生成的文件名称
                multipartFile.transferTo(new File(targetFile, fileName));
            } catch (IOException e) {
                e.printStackTrace();
                request.setAttribute("uploadFileError", " * 文件上传失败！");
                return uploadFilePath;
            }
            // 文件上传完成就可以拿到地址
            uploadFilePath = File.separator + Constants.UPLOAD_PATH + File.separator + fileName;
        }

        // 返回文件上传成功后的地址，失败时返回null，并且将失败信息记录到
        return uploadFilePath;
    }

    /**
     * 查看用户信息
     */
    @GetMapping("/view/{userId}")
    public String view(Model model, @PathVariable("userId") Long userId) {
        SysUser sysUser = sysUserService.getById(userId);
        model.addAttribute("sysUser", sysUser);
        return "sysUser/view";
    }

    /**
     * 查看用户信息（Ajax）
     */
    @ResponseBody
    @GetMapping(value = "/{userId}/view", produces = {"application/json;charset=UTF-8"})
    public String view(@PathVariable("userId") Long userId) {
        SysUser sysUser = sysUserService.getById(userId);
        if (sysUser == null) {
            return JSON.toJSONString("nodata");
        }
        return JSON.toJSONString(sysUser);
    }

    /**
     * 去修改用户页面
     */
    @GetMapping("/update")
    public String toUpdate(Model model, @RequestParam("uid") Long userId) {
        SysUser sysUser = sysUserService.getById(userId);
        model.addAttribute("sysUser", sysUser);
        return "sysUser/update";
    }

    /**
     * 修改用户信息
     */
    @PostMapping("/update")
    public String update(SysUser sysUser) {
        boolean update = sysUserService.update(sysUser);
        logger.debug("/user/update " + update + "\n" + sysUser.toString());
        return "redirect:/user/list";
    }

    /**
     * 删除用户信息
     */
    @ResponseBody
    @GetMapping("/del/{userId}")
    public String del(@PathVariable("userId") Long userId) {
        Map<String, Object> result = new HashMap<>();
        SysUser sysUser = sysUserService.getById(userId);
        if (sysUser == null) {
            result.put("delResult", "notexist");
            return JSON.toJSONString(result);
        }
        boolean del = sysUserService.delById(userId);
        logger.debug("/user/del/" + userId + " " + del);
        result.put("delResult", del ? "true" : "false");
        return JSON.toJSONString(result);
    }

    /**
     * 捕获异常信息，设置到作用域，跳转到统一的异常处理页面
     */
    // @ExceptionHandler()
    public String handlerException(RuntimeException e, HttpServletRequest request) {
        // 将异常信息设置到作用域
        request.setAttribute("e", e);
        // 跳转到统一的异常处理页面
        return "error";
    }
}
